﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using GurLoader.Service.Mailslot;
using MailSlot;
using NUnit.Framework;

namespace GurLoaderWPF.Test.Service.Mailslot
{
    [TestFixture]
    public class MailslotServiceTest
    {

        [Test]
        public void TestSendMessage()
        {
            GurLoader.Service.Mailslot.MailslotService service = new GurLoader.Service.Mailslot.MailslotService("TestEndpoint");
            MailslotClient client = new MailslotClient("TestEndpoint");
            
            service.Start();

            bool wasCalled = false;
            string messageReceived = string.Empty;
            ManualResetEvent mre = new ManualResetEvent(false);

            service.CommandReceived += (object sender, CommandEventArgs args) =>
            {
                wasCalled = true;
                messageReceived = args.Command;
                mre.Set();
            };

            string testMessageString = "A command to be sent to the listener.";
            client.SendMessage( testMessageString );

            mre.WaitOne(1000*10); // wait max of 10 seconds

            Assert.IsTrue(wasCalled);
            Assert.AreEqual(testMessageString, messageReceived);

            service.Stop();
            service.Dispose();
            client.Dispose();
        }

        [Test]
        public void DisposeNotStoppedTest()
        {
            GurLoader.Service.Mailslot.MailslotService service = new GurLoader.Service.Mailslot.MailslotService("TestEndpoint");

            Assert.IsNotNull(service);

            service.Start();
            service.Dispose();

            Assert.IsFalse(service.IsRunning);
        }

        [Test]
        public void DisposeStoppedTest()
        {
            GurLoader.Service.Mailslot.MailslotService service = new GurLoader.Service.Mailslot.MailslotService("TestEndpoint");

            Assert.IsNotNull(service);

            service.Start();
            try
            {
                service.Stop();
            }
            catch (TaskCanceledException ex)
            {
                Debug.WriteLine("Cancelled");
            }

            service.Dispose();

            Assert.IsFalse(service.IsRunning);
        }

        [Test]
        public void IsNotRunniongStatusBecauseNotStartedTest()
        {
            GurLoader.Service.Mailslot.MailslotService service = new GurLoader.Service.Mailslot.MailslotService("TestEndpoint");
            
            Assert.IsNotNull(service);

            // do not call start
            Assert.IsFalse(service.IsRunning);

            service.Stop();
            service.Dispose();
        }

        [Test]
        public void IsNotRunningStatusBecauseStoppedTest()
        {
            GurLoader.Service.Mailslot.MailslotService service = new GurLoader.Service.Mailslot.MailslotService("TestEndpoint");
            MailslotClient client = new MailslotClient("TestEndpoint");

            Assert.IsNotNull(service);

            service.Start();

            bool wasCalled = false;
            ManualResetEvent mre = new ManualResetEvent(false);

            service.CommandReceived += (object sender, CommandEventArgs args) =>
            {
                wasCalled = true;
                mre.Set();
            };

            // send a message to ensure that the thread can be created if necessary
            string testMessageString = "A command to be sent to the listener.";
            client.SendMessage(testMessageString);

            mre.WaitOne(1000 * 10); // wait max of 10 seconds

            Assert.IsTrue(service.IsRunning);

            service.Stop();

            Assert.IsFalse(service.IsRunning);

            service.Dispose();
        }

        [Test]
        public void IsRunningStatusTest()
        {
            GurLoader.Service.Mailslot.MailslotService service = new GurLoader.Service.Mailslot.MailslotService("TestEndpoint");
            MailslotClient client = new MailslotClient("TestEndpoint");

            Assert.IsNotNull(service);

            service.Start();

            bool wasCalled = false;
            ManualResetEvent mre = new ManualResetEvent(false);

            service.CommandReceived += (object sender, CommandEventArgs args) =>
            {
                wasCalled = true;
                mre.Set();
            };

            // send a message to ensure that the thread can be created if necessary
            string testMessageString = "A command to be sent to the listener.";
            client.SendMessage(testMessageString);

            mre.WaitOne(1000 * 10); // wait max of 10 seconds

            Assert.IsTrue(service.IsRunning);

            service.Stop();
            service.Dispose();            
        }

        [Test]
        [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Mailslot name must not be null or empty.")]
        public void TestEmptyMailslotName()
        {
            GurLoader.Service.Mailslot.IMailslotService service = new GurLoader.Service.Mailslot.MailslotService(string.Empty);
        }

        [Test]
        [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Polling wait time must be between 1ms and 5 mins.")]
        public void TestZeroPollingTime()
        {
            GurLoader.Service.Mailslot.IMailslotService service = new GurLoader.Service.Mailslot.MailslotService("MailslotName", 0);
        }

        [Test]
        [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Polling wait time must be between 1ms and 5 mins.")]
        public void TestTenMinutePollingTime()
        {
            GurLoader.Service.Mailslot.IMailslotService service = new GurLoader.Service.Mailslot.MailslotService("MailslotName", 1000 * 60 * 10);
        }
    }
}
